package com.github.sbb.sherry.primitives.fetcher.http;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.github.sbb.sherry.common.base.Preconditions;
import com.github.sbb.sherry.common.base.ValidateResult;
import com.github.sbb.sherry.common.collect.CollectionUtil;
import com.github.sbb.sherry.primitives.api.Fact;
import com.github.sbb.sherry.primitives.api.Facts;
import com.github.sbb.sherry.primitives.api.Fetcher;
import com.github.sbb.sherry.primitives.config.fetcher.HttpAuth;
import com.github.sbb.sherry.primitives.config.fetcher.HttpFetcherConfig;
import com.github.sbb.sherry.primitives.core.MapFact;
import com.github.sbb.sherry.primitives.exception.FetcherException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class HttpFetcher implements Fetcher {

  private final String name;
  private final HttpFetcherConfig config;
  private final HttpDataSource dataSource;
  private final boolean hasUrlParams;
  private final boolean hasBodyData;
  private HttpAuth httpAuth;

  public HttpFetcher(String name, HttpFetcherConfig config, HttpDataSource dataSource) {

    Preconditions.checkNotNull(name, "name can`t be null");
    Preconditions.checkNotNull(config, "HttpFetcherConfig can`t be null");
    Preconditions.checkNotNull(dataSource, "HttpDataSource can`t be null");

    ValidateResult validate = config.validate();
    Preconditions.checkArgument(validate.isPass(), validate.getMessage());

    this.name = name;
    this.config = config;
    this.dataSource = dataSource;
    this.hasBodyData = config.getMethod().equals("POST") && CollectionUtil.isNotEmpty(config.getData());
    this.hasUrlParams = CollectionUtil.isNotEmpty(config.getParams());
    this.httpAuth = config.getHttpAuth() != null && config.getHttpAuth().isValid() ? config.getHttpAuth() : null;
  }

  @Override
  public String name() {
    return name;
  }

  @Override
  public byte getDefaultFetchMethod() {
    return config.getDefaultFetchMethod();
  }

  @Override
  public Fact emit(Map<String, Object> params) throws FetcherException {
    String result = obtainData(params);
    Map<String, Object> resultMap = JSON.parseObject(result, new TypeReference<Map<String, Object>>() {
    });
    return new MapFact(resultMap);
  }

  /**
   * 多次查询
   *
   * @param params 查询条件
   * @return record列表
   */
  @Override
  public Facts batchEmit(Map<String, Object> params) throws FetcherException {
    String result = obtainData(params);
    List<Map<String, Object>> list = JSON.parseObject(result, new TypeReference<List<Map<String, Object>>>() {
    });
    Facts facts = new Facts();
    list.stream().map(MapFact::new).forEach(facts::add);
    return facts;
  }

  private String obtainData(Map<String, Object> params) throws FetcherException {
    try {

      Map<String, String> queryParams = null;
      Map<String, String> queryBodyData = null;

      boolean hasParam = CollectionUtil.isNotEmpty(params);

      // 处理 URL 参数
      if (hasUrlParams && hasParam) {
        // 😂 这里就不棒了，还得单独处理一下
        queryParams = new HashMap<>();
        for (Entry<String, String> entry : config.getParams().entrySet()) {
          String key = entry.getKey();
          String value = entry.getValue();

          String result = (String) params.get(value);
          if (result != null) {
            queryParams.put(key, result);
          }
        }
      }

      // 处理 Body 参数
      if (hasBodyData && hasParam) {
        // 😂 这里就不棒了，还得单独处理一下
        queryBodyData = new HashMap<>();
        for (Entry<String, String> entry : config.getData().entrySet()) {
          String key = entry.getKey();
          String value = entry.getValue();

          String result = (String) params.get(value);
          if (result != null) {
            queryBodyData.put(key, result);
          }
        }
      }
      return dataSource
          .executeCall(config.getUrl(), config.getMethod(), config.getHeaders(), queryParams, queryBodyData,
              this.httpAuth);
    } catch (Exception e) {
      throw new FetcherException(e);
    }
  }

}
